#include <QUndoStack>

#include "Line3DHandler.h"
#include "CmdManager.h"
#include "SendPointHandlerBase.h"
#include "Scene.h"
#include "Ucs.h"
#include "LineStrip3D.h"
#include "Operation/OpAdd.h"
#include "PointHandler.h"
#include "QtOSGWidget.h"

Line3DHandler::Line3DHandler()
{
}

Line3DHandler::~Line3DHandler()
{
}

void Line3DHandler::input(const QVariant& data, const QString& rawInput, CommandSource cs)
{
	auto sph = getSendPointHandler();
	auto scene = getScene();
	auto widget3D = getWidget();
	if (data.type() == QVariant::Bool && !data.toBool())
	{
		if (m_line)
		{
			widget3D->pauseRenderThread();
			scene->removeChild(m_line);
			widget3D->resumeRenderThread();
		}
		emit finished();
		return;
	}

	if (status() == 0)
	{
		if (sph)
		{
			sph->setPointMask(CS_LBTNDOWN);
		}
		m_pointStateMachine = std::make_shared<PointHandler>();
		m_pointStateMachine->setCmdManager(cmdManager());

		m_line = std::make_shared<LineStrip3D>(scene);
		m_line->setColor(getCurrentColor());
		widget3D->pauseRenderThread();
		scene->addChild(m_line);
		widget3D->resumeRenderThread();
		m_pointStateMachine->setPrompt0(tr("指定起点"));
		m_pointStateMachine->input(data, rawInput, cs);
		setStatus(1);
		return;
	}

	std::vector<osg::Vec3d> points = m_line->getPoints();
	if (status() == 1)
	{
		if (data.type() == QVariant::Bool && data.toBool())
		{
			widget3D->pauseRenderThread();
			scene->removeChild(m_line);
			widget3D->resumeRenderThread();
			emit finished();
			return;
		}
		if (sph)
		{
			sph->setPointMask(CS_LBTNDOWN | CS_MOUSEMOVE);
		}
		m_pointStateMachine->input(data, rawInput, cs);
		if (m_pointStateMachine->done())
		{
			osg::Vec3d worldPt = m_pointStateMachine->getPoint();
			points.push_back(worldPt);
			points.push_back(worldPt);
			widget3D->pauseRenderThread();
			m_line->setPoints(points);
			widget3D->resumeRenderThread();
			m_pointStateMachine->setPrompt0(tr("指定下一点或者"), QStringList() << "回退", QStringList() << "U");
			m_pointStateMachine->reset();
			setStatus(2);
		}
		return;
	}

	if (status() >= 2)
	{
		if (data.type() == QVariant::Bool && data.toBool())
		{
			if (status() == 2)
			{
				// 只有一个点，不能形成线段
				widget3D->pauseRenderThread();
				scene->removeChild(m_line);
				widget3D->resumeRenderThread();
				emit finished();
				return;
			}
			points.pop_back();
			widget3D->pauseRenderThread();
			m_line->setPoints(points);
			scene->removeChild(m_line);
			widget3D->resumeRenderThread();
			std::vector<std::shared_ptr<Ent>> lines;
			bool success = m_line->explode(lines);
			if (!success)
				lines.push_back(m_line);
			auto undoStack = scene->undoStack();
			std::set<std::shared_ptr<INode>> children;
			for (const auto& line : lines)
				children.insert(line);
			undoStack->push(new OpAdd(children));
			emit finished();
			return;
		}
		else if (data.type() == QVariant::String && data.toString().compare("U", Qt::CaseInsensitive) == 0)
		{
			osg::Vec3d last2Pt;
			if (points.size() >= 3)
				last2Pt = points[points.size() - 3];
			sph->setLastPoint(QVector3D(last2Pt.x(), last2Pt.y(), last2Pt.z()));
			set3DRubberLineP1(last2Pt);

			if (status() == 2)
			{
				points.clear();
				if (sph)
				{
					sph->setPointMask(CS_LBTNDOWN);
				}
				show3DRubberLine(false);
				prompt(1, tr("指定起点:"));
			}
			else
			{
				auto lastPt = points.back();
				points.resize(points.size() - 1);
				points.back() = lastPt;
				prompt(status() - 1, tr("指定下一点或者[回退(U)]:"));
			}
			widget3D->pauseRenderThread();
			m_line->setPoints(points);
			widget3D->resumeRenderThread();
			return;
		}

		if (cs == CS_MOUSEMOVE)
		{
			if (data.type() == QVariant::Vector3D)
			{
				auto pt = data.value<QVector3D>();
				osg::Vec3d worldPt = { pt.x(), pt.y(), pt.z() };
				points[points.size() - 1] = worldPt;
			}
			m_line->setPoints(points);
		}
		else
		{
			m_pointStateMachine->input(data, rawInput, cs);
			if (m_pointStateMachine->done())
			{
				osg::Vec3d worldPt = m_pointStateMachine->getPoint();
				points[points.size() - 1] = worldPt;
				points.push_back(worldPt);
				widget3D->pauseRenderThread();
				m_line->setPoints(points);
				widget3D->resumeRenderThread();
				m_pointStateMachine->setPrompt0(tr("指定下一点或者"), QStringList() << "回退", QStringList() << "U");
				setStatus(status() + 1);
				m_pointStateMachine->reset();
			}
		}
		return;
	}
}